/*
    Linear Programming Library
    
    Created by Team Paragon (Shena Hoffmann, Arthur Powalka, Nasir Kenarangui)
    CSCE 689
    
    main.cpp
    Contains various examples of how to use the linear programming library.
*/

#include "Simplex.h"
#include "RevSimplex.h"
#include "Karmarkar.h"
#include <chrono>

using namespace chrono;

//NOTE: use the following command to run this main file with all of the library classes:
// g++ -std=c++11 LinProg.cpp Exceptions.cpp Karmarkar.cpp Simplex.cpp RevSimplex.cpp main.cpp -g -larmadillo

//print vectors for testing outputs
template<typename type>
void print_vector(vector<type> vec)
{
	for_each(vec.begin(), vec.end(), [](type value){cout<<"\t"<<value<<"\t";});
	cout<<endl;
}

void printTuple(const tuple<vector<double>, string, double> &solutionData)
{
	cout<<"The variables are : ";
	print_vector(get<0>(solutionData));
	cout<<"This solution is : "<<get<1>(solutionData)<<endl;
	cout<<"The optimal value of the objective is : "<<get<2>(solutionData)<<endl;
	cout<<endl;
}


int main()
{	/* //MAIN TIMINGS IN THIS LARGE SECTION
	double numIterations=100;
	LinProg p1;	
	p1.setMaximum(true);
	p1.setObjective( { 4, -2, 2 });
	vector<double> eq1 = { 3, 1, 1 };
	vector<double> eq2 = { 1, -1, 2 };
	vector<double> eq3 = { 1, 1, -1 };
	p1.setConstraints( { eq1, eq2, eq3 });
	p1.setInequalitySigns( { "<=", "<=", "<=" });
	p1.setInequalityVals( { 180, 30, 60 });
	p1.setConstrainedVars( {true,true,true});

	Simplex sProblem1(p1);
	Karmarkar kProblem1(p1);
	RevSimplex rProblem1(p1);	
	p1.printLinProg();
		auto t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			sProblem1.solve();	
		}
		auto t2 = system_clock::now();
		auto dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Tableau Simplex time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			kProblem1.solve();
		}
		
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Karmarkar time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			rProblem1.solve();
		}
		//printTuple(rProblem1.solve());
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Revised Simplex time " << dms1.count()/numIterations << " microseconds\n";
		cout<<endl;


	LinProg p2;	
	p2.setMaximum(true);
	p2.setObjective( { 5, 4, 3 });
	eq1 = { 2, 3, 1 };
	eq2 = { 4, 1, 2 };
	eq3 = { 3, 4, 2 };
	p2.setConstraints( { eq1, eq2, eq3 });
	p2.setInequalitySigns( { "<=", "<=", "<=" });
	p2.setInequalityVals( { 5, 11, 8 });
	p2.setConstrainedVars( {true,true,true});

	Simplex sProblem2(p2);
	Karmarkar kProblem2(p2);
	RevSimplex rProblem2(p2);	
	p2.printLinProg();
		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			sProblem2.solve();	
		}
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Tableau Simplex time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			kProblem2.solve();
		}
		
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Karmarkar time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			rProblem2.solve();
		}
		//printTuple(rProblem1.solve());
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Revised Simplex time " << dms1.count()/numIterations << " microseconds\n";	
		cout<<endl;

	LinProg p3;	
	p3.setMaximum(true);
	p3.setObjective( { 2, 1.5 });
	eq1 = { 6, 3 };
	eq2 = { 0.75,1 };
	p3.setConstraints( { eq1, eq2 });
	p3.setInequalitySigns( { "<=", "<=" });
	p3.setInequalityVals( { 1200, 250 });
	p3.setConstrainedVars( {true,true});

	Simplex sProblem3(p3);
	Karmarkar kProblem3(p3);
	RevSimplex rProblem3(p3);	
	p3.printLinProg();
		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			sProblem3.solve();	
		}
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Tableau Simplex time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			kProblem3.solve();
		}
		
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Karmarkar time " << dms1.count()/numIterations << " microseconds\n";

		t1 = system_clock::now();
		for(int i=0;i<numIterations;i++)
		{
			rProblem3.solve();
		}
		t2 = system_clock::now();
		dms1 = duration_cast<microseconds>(t2-t1);		
		cout << "Average Revised Simplex time " << dms1.count()/numIterations << " microseconds\n";	
		cout<<endl;
		printTuple(rProblem3.solve());

			
*/
	
	//good example
/*
	LinProg p;	
	p.setMaximum(false);
	p.setObjective( { 3, 2 });
	vector<double> eq1 = { 2, 1 };
	vector<double> eq2 = { 1,1 };
	p.setConstraints( { eq1, eq2});
	p.setInequalitySigns( { ">=", ">=" });
	p.setInequalityVals( { 6, 4 });
	p.setConstrainedVars( {true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());

*/



//alternate version of the one above

//alternate version of the example one above

/*
	Karmarkar kProblem;		//this creates an empty karmarkar object
	kProblem.setMaximum(true);		//specifies a Maximization Problem
	kProblem.setObjective( { 4, -2, 2 });		//sets the objective equation’s coefficients
	vector<double> eq1 = { 3, 1, 1 };		//creates the coefficients for the first constraint
	vector<double> eq2 = { 1, -1, 2 };
	vector<double> eq3 = { 1, 1, -1 };
	kProblem.setConstraints( { eq1, eq2, eq3 });	//sets the constraints for the problem
	kProblem.setInequalitySigns( { "<=", "<=", "<=" });	     // indicates the sign of the constraints
	kProblem.setInequalityVals( { 180, 30, 60 });	//sets the right sides of the constraints
	kProblem.setConstrainedVars( {true,true,true});	//indicates which variables are constrained

	printTuple(kProblem.solve()); 	//the solve function will find an optimal solution
	Karmarkar standardForm=kProblem.convertToStandardForm();
	standardForm.printLinProg();	//will print the standard form of 
*/	

/*
	LinProg p;	
	p.setMaximum(true);
	p.setObjective( { 50, 75, 60 });
	vector<double> eq1 = { 5, 3, 1 };
	vector<double> eq2 = { -5, 6, 15 };
	vector<double> eq3 = { 2, 1, 1 };
	p.setConstraints( { eq1, eq2, eq3 });
	p.setInequalitySigns( { "<=", "<=", ">=" });
	p.setInequalityVals( { 144, 240, 80 });
	p.setConstrainedVars( {true,true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());	
	
*/
/*
LinProg p;	
p.setMaximum(true);
p.setObjective( { 3, 5 });
vector<double> eq1 = { 1, 0 };
vector<double> eq2 = { 0, 2 };
vector<double> eq3 = { 3, 2 };
p.setConstraints( { eq1, eq2, eq3 });
p.setInequalitySigns( { "<=", "=", ">=" });
p.setInequalityVals( { 4, 12, 18 });
p.setConstrainedVars( {true,true});
Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);
printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());	
*/	

/*
	LinProg p;	
	p.setMaximum(true);
	p.setObjective( { 4, -2, 2 });
	vector<double> eq1 = { 3, 1, 1 };
	vector<double> eq2 = { 1, -1, 2 };
	vector<double> eq3 = { 1, 1, -1 };
	p.setConstraints( { eq1, eq2, eq3 });
	p.setInequalitySigns( { "<=", "<=", "<=" });
	p.setInequalityVals( { 180, 30, 60 });
	p.setConstrainedVars( {true,true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());	
*/	
/*
	LinProg p;	
	p.setMaximum(true);
	p.setObjective( { 3, 1, 5, 4 });
	vector<double> eq1 = { 3, -3, 2, 8 };
	vector<double> eq2 = { 5, 6, -4, -4 };
	vector<double> eq3 = { 4, -2, 1, 3 };
	p.setConstraints( { eq1, eq2, eq3 });
	p.setInequalitySigns( { "<=", "<=", "<=" });
	p.setInequalityVals( { 50, 40, 20 });
	p.setConstrainedVars( {true,true,true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());	
*/
/*
	LinProg p;	
	p.setMaximum(true);
	p.setObjective( { 1, 1, 1, 1 });
	vector<double> eq1 = { 1, 1, 0, 0};
	vector<double> eq2 = { 0, 0, 1, 1 };
	p.setConstraints( { eq1, eq2 });
	p.setInequalitySigns( { "<=", "<=" });
	p.setInequalityVals( { 3, 2 });
	p.setConstrainedVars( {true,true,true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());	
*/
		//test the example below!!!
/*
	LinProg p;	
	p.setMaximum(false);
	p.setObjective( { 3, 2 });
	vector<double> eq1 = { 2, 1 };
	vector<double> eq2 = { 1,1 };
	p.setConstraints( { eq1, eq2});
	p.setInequalitySigns( { ">=", ">=" });
	p.setInequalityVals( { 6, 4 });
	p.setConstrainedVars( {true,true});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());

*/
	
	LinProg p;	//has one solution. will need to subtract x2 and x3 from each other... that is just how an unconstrained solution works
	p.setMaximum(true);
	p.setObjective( { 3, 5 });
	vector<double> eq1 = { 1, 0};
	vector<double> eq2 = { 0, 2 };
	vector<double> eq3 = { 3, 2 };
	p.setConstraints( { eq1, eq2, eq3 });
	p.setInequalitySigns( { "<=", "=", ">=" });
	p.setInequalityVals( { 4, 12, 8 });
	p.setConstrainedVars( {true,false});

	Simplex s_problem(p);
	Karmarkar k_problem(p);
	RevSimplex r_problem(p);	
	s_problem.printLinProg();
	printTuple(s_problem.solve());	
	cout<<"Need to subtract x_2 and x_3 for this problem. We introduced an extra variable since one of the variables was unconstrained. x_2=x_2-x_3"<<endl;
	printTuple(k_problem.solve());	
	printTuple(r_problem.solve());

/*	//debugging the above
	//issue fixed
	LinProg p1;	
	p1.setMaximum(true);
	p1.setObjective( { 3, 5, -3 });
	eq1 = { 1, 0, -1};
	eq2 = { 0, 2, 0 };
	eq3 = { 3, 2, -3 };
	p1.setConstraints( { eq1, eq2, eq3 });
	p1.setInequalitySigns( { "<=", "=", ">=" });
	p1.setInequalityVals( { 4, 12, 8 });
	p1.setConstrainedVars( {true,true,true});

	Simplex s_problem1(p1);
	Karmarkar k_problem1(p1);	
	s_problem1.printLinProg();
	printTuple(s_problem1.solve());	
	printTuple(k_problem1.solve());	
*/

}
